Offshift ware Write Up
Details:
Points: 500
Jeopardy style CTF
Category: Reversing
Comment: My plaintext has been encrypted by an innocent friend of mine while playing around cryptographic libraries, can you help me to recover the plaintext , remembers it's just numbers and there's a space between some numbers which you need to remove the space and submit the recovered plain text as a flag.
Write up:
As I do with most reversing challenges I started by running strings on the file. This resulted in a result that contained:
5U/3Q
mU64
X(%MPWA
/usr/
/go-1.6/
-gdb
UPX!
UPX!
(x8#
Seeing the UPX let me realize that I would need to unpack using UPX before starting to reverse.
UPX -d skidw4re
After unpacking I ran file and found that it was a 32 bit program.
$ file skidw4re
skidw4re: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, no section header
I then ran the program to see what the output was:
$ ./skidw4re
This is the only message--------> ae385c6f1dd72132b2afcd4c25b9d35e0000000000000000
32 The message has been encrypted and written
I then loaded the program into IDA.
void __cdecl main_main()
{
os_File *v0; // eax
uintptr v1; // eax
interface_{} *v2; // ebx
uintptr v3; // eax
interface_{} *v4; // ebx
uintptr v5; // eax
interface_{} *v6; // ebx
uintptr v7; // eax
interface_{} *v8; // ebx
int v9; // eax
_BYTE name[24]; // [esp+0h] [ebp-5Ch] BYREF
int elem; // [esp+18h] [ebp-44h] BYREF
os_File *f; // [esp+1Ch] [ebp-40h]
error_0 err; // [esp+20h] [ebp-3Ch]
int v14; // [esp+28h] [ebp-34h]
uintptr v15; // [esp+2Ch] [ebp-30h]
int v16; // [esp+30h] [ebp-2Ch] BYREF
int v17; // [esp+34h] [ebp-28h]
int v18[2]; // [esp+38h] [ebp-24h] BYREF
__interface_{} a; // [esp+40h] [ebp-1Ch]
int v20[4]; // [esp+4Ch] [ebp-10h] BYREF
void *retaddr; // [esp+5Ch] [ebp+0h] BYREF
while ( (unsigned int)&retaddr <= *(_DWORD *)(*(_DWORD *)(__readgsdword(0) - 4) + 8) )
runtime_morestack_noctxt();
main_Encryptfinal();
*(_DWORD *)name = "encryptedmessage.txt";
*(_DWORD *)&name[4] = 20;
os_Create(*(string *)name, *(os_File **)&name[8], *(error_0 *)&name[12]);
v0 = *(os_File **)&name[8];
err = *(error_0 *)&name[12];
if ( *(_DWORD *)&name[12] )
{
v16 = 0;
v17 = 0;
if ( name == (_BYTE *)-48 )
v16 = *(_DWORD *)&name[8];
a.len = 1;
a.cap = 1;
...
Looking over the top of the main function I noticed the main_Encryptfinal method and decided to click on it.
void main_Encryptfinal()
{
int v0; // eax
uintptr v1; // eax
interface_{} *v2; // ebx
_BYTE buf[28]; // [esp+0h] [ebp-84h] BYREF
uint8 v4[32]; // [esp+1Ch] [ebp-68h] BYREF
string pt; // [esp+3Ch] [ebp-48h]
string key; // [esp+44h] [ebp-40h]
string c; // [esp+4Ch] [ebp-38h]
int v8; // [esp+54h] [ebp-30h]
uintptr v9; // [esp+58h] [ebp-2Ch]
int v10[2]; // [esp+5Ch] [ebp-28h] BYREF
int elem[2]; // [esp+64h] [ebp-20h] BYREF
__interface_{} a; // [esp+6Ch] [ebp-18h]
int v13; // [esp+78h] [ebp-Ch]
int v14; // [esp+7Ch] [ebp-8h]
int v15; // [esp+80h] [ebp-4h] BYREF
while ( (unsigned int)&v15 <= *(_DWORD *)(*(_DWORD *)(__readgsdword(0) - 4) + 8) )
runtime_morestack_noctxt();
pt.str = (uint8 *)"321174068998067 98980909";
pt.len = 24;
key.str = (uint8 *)"thisis32bitlongpassphraseimusing";
*(_DWORD *)&buf[4] = "thisis32bitlongpassphraseimusing";
key.len = 32;
*(_DWORD *)&buf[8] = 32;
runtime_stringtoslicebyte((uint8 (*)[32])v4, *(string *)&buf[4], *(__uint8 *)&buf[12]);
v13 = *(_DWORD *)&buf[12];
*(_DWORD *)buf = *(_DWORD *)&buf[12];
v14 = *(_DWORD *)&buf[16];
*(_DWORD *)&buf[4] = *(_DWORD *)&buf[16];
v15 = *(_DWORD *)&buf[20];
*(_DWORD *)&buf[8] = *(_DWORD *)&buf[20];
main_EncryptAES(*(__uint8 *)buf, pt, *(string *)&buf[20]);
*(_DWORD *)&buf[8] = 34;
c = *(string *)&buf[20];
*(_DWORD *)&buf[12] = *(_DWORD *)&buf[20];
*(_DWORD *)&buf[16] = *(_DWORD *)&buf[24];
runtime_concatstring2(0, (string *)"This is the only message--------> ", *(string *)&buf[8]);
elem[0] = *(_DWORD *)&buf[20];
elem[1] = *(_DWORD *)&buf[24];
v10[0] = 0;
v10[1] = 0;
if ( buf == (_BYTE *)-92 )
v10[0] = v0;
a.len = 1;
a.cap = 1;
a.array = (interface_{} *)v10;
runtime_convT2E((runtime__type_0 *)&stru_80F1F00, elem, 0, *(runtime_eface_0 *)&buf[12]);
v1 = *(_DWORD *)&buf[16];
v2 = a.array;
v8 = *(_DWORD *)&buf[12];
a.array->_type = *(runtime__type_0 **)&buf[12];
v9 = v1;
if ( runtime_writeBarrier.enabled )
runtime_writebarrierptr((uintptr *)&v2->data, v1);
else
v2->data = (void *)v1;
fmt_Println(a, *(__int32 *)&buf[12], *(error_0 *)&buf[16]);
}
Here I noticed pt.str, since this was an encryption function I assumed pt stood for plain text, and the string matched the format the comment specified.
The flag ended up being:
flag{32117406899806798980909}